# coding:utf-8
import socketio
import threading
import platform
import os
import time
import subprocess
import traceback
import signal
sio = socketio.Client()
key = 'lixin'
process = {}
def read_error(p,sid):
    while True:
        try:
            error = p.stderr.readline()
            if not error:
                continue
            result = error.decode('GBK').strip()
            callback_exec_command(result,sid)
        except:
            traceback.print_exc()
        finally:
            if process[sid]['status'] == 0:
                print('exit;')
                break

def read_out(p,sid):
    while True:
        try:
            out = p.stdout.readline()
            if not out:
                continue
            result = out.decode('GBK').strip()
            callback_exec_command(result, sid)
        except:
            traceback.print_exc()
        finally:
            if process[sid]['status'] == 0:
                print('exit;')
                break

def callback_exec_command(result,sid):
    try:
        sio.emit('execute result', {'result': result, 'admin_sid': sid,'client_sid':sio.sid})
    except:
        traceback.print_exc()


@sio.event
def message(data):
    print('I received a message!')
    print(data)


@sio.on('message')
def on_message(data):
    print('I received a message!')
    print(data)


@sio.on('exec command')
def exec_command(data):
    print(process.keys())
    admin_sid = data['admin_sid']
    if admin_sid not in process.keys():
        p = subprocess.Popen('cmd.exe', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        out_thread = threading.Thread(target=read_out,args=(p,admin_sid))
        err_thread = threading.Thread(target=read_error,args=(p,admin_sid))
        process[admin_sid] = {
            'ctime': time.time(),
            'atime': time.time(),
            'p': p,
            'out_thread':out_thread,
            'err_thread':err_thread,
            'status':1
        }
        out_thread.start()
        err_thread.start()
    else:
        p = process[admin_sid]['p']
    if data['command'] == 'Ctrl+C':
        print('pid:',p.pid)
        os.kill(p.pid, signal.CTRL_C_EVENT)
    elif data['command'] == 'EXIT':
        os.kill(p.pid, signal.CTRL_C_EVENT)
        time.sleep(0.1)
        os.kill(p.pid, signal.CTRL_C_EVENT)
        p.stdin.write('exit'.encode())
        p.stdin.write(''.encode())
        p.stdin.flush()
    else:
        p.stdin.write((data['command'] + os.linesep).encode('GBK'))
        p.stdin.flush()

@sio.on('admin exit')
def exec_command(data):
    admin_sid = data['sid']
    process[admin_sid]['status'] = 0


@sio.event
def connect(msg=''):
    print('msg:', msg)
    sio.emit('join host', {'key': key})


@sio.event
def connect_error(msg=''):
    print('error:',msg)
    print("The connection failed!")


@sio.event
def disconnect():
    print("I'm disconnected!")
    # sio.connect('http://127.0.0.1:5000', namespaces=['/'])


sio.connect('http://127.0.0.1:5000', namespaces=['/'])
print('my sid is', sio.sid)

